package com.zhuangjie.shop.helper;

import com.zhaungjie.base.utils.StringUtils;
import com.zhuangjie.base.constant.CommonSeparatorConstants;
import com.zhuangjie.coupon.enums.CouponApplicationLogicType;
import com.zhuangjie.coupon.enums.CouponApplicationType;
import com.zhuangjie.coupon.enums.CouponType;
import com.zhuangjie.coupon.pojo.CouponCoreInfo;
import com.zhuangjie.shop.dto.CartItemDTO;
import com.zhuangjie.shop.vo.CartItemVO;

import java.math.BigDecimal;
import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.Stream;

public class CouponHelper {

    /**
     * 优惠券可用性检查
     *
     * @param cartItemVOList 购物车项目列表
     * @param couponList     优惠券清单
     * @return {@link List}<{@link CouponCoreInfo}>
     */
    public static List<CouponCoreInfo> couponAvailabilityCheck(List<CartItemVO> cartItemVOList, List<CouponCoreInfo> couponList) {
        return couponList.stream().filter(coupon->{
            // 看是否通过指定的类别或商品
            List<CartItemVO> applicableCartItemList = filterApplicableDishList(coupon, cartItemVOList);
            if (applicableCartItemList.isEmpty()) {
                // 如果优惠券没有适用的商品，那该优惠券不可用
                return false;
            }
            // 计算适用商品的和（菜品*数量 + ...）
            BigDecimal applicableProductListSumAmount = applicableCartItemList.stream().map(CartItemDTO::getPrice).reduce(BigDecimal.ZERO, BigDecimal::add);
            // 如果是满减，还有门槛限制，需要检查
            if (Objects.equals(coupon.getType(), CouponType.FULL_REDUCTION.getCode()) && applicableProductListSumAmount.compareTo(coupon.getThresholdAmount()) < 0) {
                return false;
            }
            // 折扣，肯定是可以的
            return true;
        }).collect(Collectors.toList());
    }

    /**
     * 过滤适用菜品
     *
     * @param couponCoreInfo 优惠券核心信息
     * @param cartItemVOList 购物车项目列表
     * @return {@link List}<{@link CartItemVO}>
     */
    public static List<CartItemVO> filterApplicableDishList(CouponCoreInfo couponCoreInfo, List<CartItemVO> cartItemVOList) {
        // 无限制，全部商品适用
        if (Objects.equals(couponCoreInfo.getApplicableType(), CouponApplicationType.NO_LIMIT.getCode())) {
            return cartItemVOList;
        }
        // 有限制，部分商品适用
        return cartItemVOList.stream().filter(cartItemVO->{
            String applicableValues = couponCoreInfo.getApplicableValues();
            // 判断逻辑类型
            Boolean isResultReversed = Objects.equals(couponCoreInfo.getApplicableLogic(), CouponApplicationLogicType.NOT_APPLICABLE_SELECTION);
            // 选择的为空，当逻辑是选择的适用的，那就返回false；如果是选择的商品不适用的否则返回true
            if (StringUtils.isBlank(applicableValues)) {
                return isResultReversed;
            }
            Stream<Long> idsStream = Arrays.stream(applicableValues.split(CommonSeparatorConstants.MULTIPLE_SEPARATOR)).map(Long::valueOf);
            if (Objects.equals(couponCoreInfo.getApplicableType(), CouponApplicationType.APPLICABLE_CATEGORY.getCode())) {
                // 限制适用类别
                return idsStream.anyMatch(id -> Objects.equals(id,cartItemVO.getDishCategoryId())) && !isResultReversed;
            }else if (Objects.equals(couponCoreInfo.getApplicableType(), CouponApplicationType.APPLICABLE_GOODS.getCode())){
                // 限制适用商品
                return idsStream.anyMatch(id -> Objects.equals(id,cartItemVO.getId())) && !isResultReversed;
            }
            // 限制了不存在的
            return false;
        }).collect(Collectors.toList());
    }

    /**
     * 优惠券最佳优惠金额计算
     * @param usableShopCoupons
     * @param cartItemVOList
     * @param dishListActivityDeductionAmount
     * @return
     */
    public static Map<Long, BigDecimal> couponDeductionAmountCalculation(List<CouponCoreInfo> usableShopCoupons, List<CartItemVO> cartItemVOList, BigDecimal dishListActivityDeductionAmount) {
        if (usableShopCoupons == null) return new HashMap<>();
        // 先聚合优惠券
        usableShopCoupons = aggCouponCoreInfo(usableShopCoupons);
        // 转为优惠券id-最佳可优惠金额（当存在多个batchId覆盖，因为这里计算的是基础优惠券，即使是膨胀券也看作基础券即可，至于膨胀是否可用，前端判断来是以基础券方法还是以膨胀券方式提交表单）
        return usableShopCoupons.stream().collect(Collectors.toMap(CouponCoreInfo::getBatchId,coupon->{
            // 如果是满减券，那value-的parValue是里面的parValue
            if (Objects.equals(coupon.getType(), CouponType.FULL_REDUCTION.getCode())) return coupon.getParValue();
            // 如果是折扣券，那value是就选当前菜品能满足的最高优惠（最佳折扣）
            // 获取可满足该折扣券要求的菜品（这里必然不为空，因为之前已经过滤了）
            Map<BigDecimal, Long> preferentialDishIdMap = filterApplicableDishList(coupon, cartItemVOList).stream().collect(Collectors.toMap(cartItem -> cartItem.getPrice().multiply(coupon.ifDiscountCouponParValue()), CartItemVO::getId));
            // 根据可优惠金额，获取最高优惠金额（菜品可优惠金额-降序）
            List<BigDecimal> sortedPreferentialDishAmountList = preferentialDishIdMap.keySet().stream().sorted(Comparator.reverseOrder()).collect(Collectors.toList());
            // 最佳优惠金额
            for (BigDecimal currentPreferentialAmount : sortedPreferentialDishAmountList) {
                if (dishListActivityDeductionAmount.compareTo(currentPreferentialAmount) >= 0) {
                    return currentPreferentialAmount;
                }
            }
            throw new RuntimeException("运算出错，无法得到商品折扣券的最佳可优惠金额！");
        },(oldValue, newValue)->newValue));
    }

    /**
     * 聚合
     * @param usableShopCoupons
     * @return
     */
    private static List<CouponCoreInfo> aggCouponCoreInfo(List<CouponCoreInfo> usableShopCoupons) {
        if (usableShopCoupons == null) return new ArrayList<>();
        return usableShopCoupons.stream().distinct().collect(Collectors.toList());
    }



}
